#include "ble.h"
#include "lib_string.h"

//Constant definition 
#define ADV_DATA_SIZE                                 20 
#define SERIAL_NAME_SIZE                              6
#define INVALID_HANDLE                                (0xFFFF)
#define AVD_INTERVAL                                  200//ms
#define ADV_INTERVAL_TO_MS(x)                         ((uint32) (((x) * 1000) / 625))

#define CONNECT_INTERVAL_MIX													12//MS
#define CONNECT_INTERVAL_MAX													30//MS
#define CONNECT_TIMEOUT_MAX													3000//MS
#define CONNECT_INTERVAL_TO_MS(x)                         ((uint32) (((x) * 1000) / 1250))
#define CONNECT_TIMEOUT_TO_MS(x)                         	((uint32) (x/10)
#define CONNECT_LATENCY																						0
#define CONNECT_MS_TO_INTERVAL(x)                         ((uint32) (((x) * 1250) / 1000))
#define CONNECT_MS_TO_TIMEOUT(x)                         	((uint32) (x*10)

#define ENV_SENS_SERVICE_UUID   0xfb,0x34,0x9b,0x5f,0x80,0x00,0x00,0x80,0x00,0x10,0x00,0x00,0x00,0xf0,0x00,0x00
#define TEMP_CHAR_UUID          0xfb,0x34,0x9b,0x5f,0x80,0x00,0x00,0x80,0x00,0x10,0x00,0x00,0x00,0xf0,0x00,0x01
#define PRESS_CHAR_UUID         0xfb,0x34,0x9b,0x5f,0x80,0x00,0x00,0x80,0x00,0x10,0x00,0x00,0x00,0xf0,0x01,0x01
#define NUM_LINKS								1

/* Client Configuration Characteristics Descriptor Definition: free fall characteristic  */
BLE_GATT_SRV_CCCD_DECLARE(cgmcomm,
			  NUM_LINKS,
			  BLE_GATT_SRV_CCCD_PERM_DEFAULT,
			  BLE_GATT_SRV_OP_MODIFIED_EVT_ENABLE_FLAG);

/* Client Configuration Characteristics Descriptor Definition: acceleration characteristic*/
BLE_GATT_SRV_CCCD_DECLARE(cgmmanage,
			  NUM_LINKS,
			  BLE_GATT_SRV_CCCD_PERM_DEFAULT,
			  BLE_GATT_SRV_OP_MODIFIED_EVT_ENABLE_FLAG);

//Private variable definition
static uint8_t m_u8_AdvData[] =
{
	0x02,0x01,0x06,
	0x03,0x02,0x00,0xF0,
	0x17,0xFF,0xA9,0x00,  
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x82
};
static uint8_t m_u8_AdvResponseData[] =
{
	0x06,0x09,'2','2','2','2','2',
	//		0x0B,0xFF,0xA9,0x00,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0x00 ,
	0x11,0x06,0x8a,0x97,0xf7,0xc0,0x85,0x06,0x11,0xe3,0xba,0xa7,0x08,0x00,0x20,0x0c,0x9a,0x66
};

static uint16 m_u16_AdvLength = 11;
static uint16 m_u16_ConnectHandle = INVALID_HANDLE;
static uint8 * m_u8p_SerialName = m_u8_AdvResponseData +  11;
static uint8 * m_u8p_Hypo = m_u8_AdvResponseData + 17;
static uint8 * m_u8p_Hyper = m_u8_AdvResponseData + 18;
static fp_on_write m_fp_OnWrite = NULL;
static fp_on_connect m_fp_OnConnect = NULL;
static Advertising_Set_Parameters_t Advertising_Set_Parameters[1];
static uint16 m_u16_Mtu = 23;
static uint16 m_u16_ConnectInterval = 0;
static uint16 m_u16_ConnectLatency = CONNECT_LATENCY;
static uint16 m_u16_ConnectTimeout = CONNECT_TIMEOUT_MAX;


static uint16 cgmSensServHandle, cgmcommCharHandle, cgmmanageCharHandle;
static ble_gatt_chr_def_t env_chars[] = {
	{/* Temperature Characteristic */
		.properties = BLE_GATT_SRV_CHAR_PROP_NOTIFY|BLE_GATT_SRV_CHAR_PROP_WRITE_NO_RESP|BLE_GATT_SRV_CHAR_PROP_WRITE,
		.permissions = BLE_GATT_SRV_PERM_NONE,
		.min_key_size = BLE_GATT_SRV_MAX_ENCRY_KEY_SIZE,
		.uuid = BLE_UUID_INIT_128(TEMP_CHAR_UUID),
		.descrs = {
			.descrs_p = &BLE_GATT_SRV_CCCD_DEF_NAME(cgmcomm),
			.descr_count = 1,
		},
	},
	{/* Pressure Characteristic */
		.properties = BLE_GATT_SRV_CHAR_PROP_NOTIFY|BLE_GATT_SRV_CHAR_PROP_WRITE_NO_RESP|BLE_GATT_SRV_CHAR_PROP_WRITE,
		.permissions = BLE_GATT_SRV_PERM_NONE,
		.min_key_size = BLE_GATT_SRV_MAX_ENCRY_KEY_SIZE,
		.uuid = BLE_UUID_INIT_128(PRESS_CHAR_UUID),
		.descrs = {
			.descrs_p = &BLE_GATT_SRV_CCCD_DEF_NAME(cgmmanage),
			.descr_count = 1,
		},
	},
};

static ble_gatt_srv_def_t env_service = {
	.type = BLE_GATT_SRV_PRIMARY_SRV_TYPE,
	.uuid = BLE_UUID_INIT_128(ENV_SENS_SERVICE_UUID),
	.chrs = {
		.chrs_p = env_chars,
		.chr_count = 2U,
	},
};




//Private function declaration
static void Ble_LoadSerialNumber(void) ;
static void Ble_StartAdv(void) ;
static void Ble_OnEvent
(
ble_event event ,uint16 para1,uint16 para2,uint16 para3
);
static uint Add_CGM_Sensor_Service(void) ;

//Public function definition   

void Ble_AppProcess(void)
{
	
}

uint Ble_InitAdv(void)
{
	uint8_t ret;
	
	LOG_INFO("Ble_InitAdv");
	uint16_t service_handle, dev_name_char_handle, appearance_char_handle;
	
	aci_hal_set_tx_power_level(0, 24);
	
	/* GATT Init */
	ret = aci_gatt_srv_init();
	if (ret != BLE_STATUS_SUCCESS) {
		LOG_INFO("aci_gatt_srv_init() failed: 0x%02x\r\n", ret);
		return ret;
	}
	
	/* GAP Init */
	ret = aci_gap_init(GAP_PERIPHERAL_ROLE, 0, 0x07, STATIC_RANDOM_ADDR, &service_handle, &dev_name_char_handle, &appearance_char_handle);
	if (ret != BLE_STATUS_SUCCESS) {
		LOG_INFO("aci_gap_init() failed: 0x%02x\r\n", ret);
		return ret;
	}
	
	/* Update device name */
	Gap_profile_set_dev_name(0, SERIAL_NAME_SIZE, &m_u8_AdvResponseData[2]);
	
	ret = aci_gap_set_authentication_requirement(NO_BONDING,
						     MITM_PROTECTION_NOT_REQUIRED,
						     SC_IS_NOT_SUPPORTED,
						     KEYPRESS_IS_NOT_SUPPORTED,
						     7, 
						     16,
						     0x00,
						     0);
	if(ret != BLE_STATUS_SUCCESS) {
		LOG_INFO("aci_gap_set_authentication_requirement()failed: 0x%02x\r\n", ret);
		return ret;
	}
	
	aci_gap_set_advertising_configuration( 0, GAP_MODE_GENERAL_DISCOVERABLE,
					      ADV_PROP_CONNECTABLE|ADV_PROP_SCANNABLE|ADV_PROP_LEGACY,
					      ADV_INTERVAL_TO_MS(AVD_INTERVAL), ADV_INTERVAL_TO_MS(AVD_INTERVAL), 
					      ADV_CH_ALL,
					      0,NULL,
					      ADV_NO_WHITE_LIST_USE,
					      0, /* 0 dBm */
					      LE_1M_PHY, /* Primary advertising PHY */
					      0, /* 0 skips */
					      LE_1M_PHY, /* Secondary advertising PHY. Not used with legacy advertising. */
					      0, /* SID */
					      0 /* No scan request notifications */);
	
	Ble_UpdateAdvData(0,20);
	Ble_StartAdv() ;
	
	//  /* Add Environmental Sensor Service */
	ret = Add_CGM_Sensor_Service();
	if(ret == BLE_STATUS_SUCCESS) {
		LOG_INFO("Environmental service added successfully.\n");
	} else {
		LOG_INFO("Error while adding Environmental service: 0x%04x\r\n", ret);
		return ret;
	}
	
	ret = OTA_Add_Btl_Service();
	if(ret == BLE_STATUS_SUCCESS)
		LOG_INFO("OTA service added successfully.\n");
	else
		LOG_INFO("Error while adding OTA service.\n");
	return BLE_STATUS_SUCCESS;
}

void Ble_UpdateAdvData
(
uint8 * u8p_Data,
uint16 u16_Length
)
{
	if(u16_Length > ADV_DATA_SIZE)
		return;
	m_u16_AdvLength = 11 + u16_Length;
	aci_gap_set_advertising_data( 0, ADV_COMPLETE_DATA, m_u16_AdvLength, m_u8_AdvData);
	aci_gap_set_scan_response_data(0,sizeof(m_u8_AdvResponseData),m_u8_AdvResponseData);
}

void Ble_AttributeNotify
(
uint16 u16_AttHandle,  
uint8 *u8p_Data, 
uint16 u16_Len
)
{
	if(m_u16_ConnectHandle != INVALID_HANDLE)
		aci_gatt_srv_notify(m_u16_ConnectHandle, cgmcommCharHandle + 1, 0, u16_Len, (uint8 *)u8p_Data);
}

void TaskRF_ManageMentNotify
(
uint16 u16_AttHandle,  
uint8 *u8p_Data, 
uint16 u16_Len
)
{
	if(m_u16_ConnectHandle != INVALID_HANDLE)
		aci_gatt_srv_notify(m_u16_ConnectHandle, cgmmanageCharHandle + 1, 0, u16_Len, (uint8 *)u8p_Data);
}

uint Ble_SetConfig
(
uint ui_Parameter,
uint8 *u8p_Value,
uint ui_Length
)
{
	switch (ui_Parameter)
	{
	    case BLE_PARAM_RESP_DATA_SERIAL_NAME:
		if(ui_Length != SERIAL_NAME_SIZE)
			return FUNCTION_FAIL;
		Lib_Memcpy(m_u8p_SerialName,u8p_Value,ui_Length);
		break;
	    case BLE_PARAM_RESP_DATA_HYPO:
		*m_u8p_Hypo = *u8p_Value;
		break;
	    case BLE_PARAM_RESP_DATA_HYPER:
		*m_u8p_Hyper = *u8p_Value;
		break;   
	    case BLE_PARAM_CALLBACK_ON_WRITE:
		if(ui_Length != sizeof(fp_on_write))
			return FUNCTION_FAIL;
		m_fp_OnWrite = (fp_on_write)u8p_Value;
		break; 
	    case BLE_PARAM_CALLBACK_ON_CONNECT:
		if(ui_Length != sizeof(fp_on_connect))
			return FUNCTION_FAIL;
		m_fp_OnConnect = (fp_on_connect)u8p_Value;
		break;
		
	    default:
		break;
	}
	return FUNCTION_OK;
}

uint Ble_GetConfig
(
uint ui_Parameter,
uint8 *u8p_Value,
uint ui_Length
)
{
	switch (ui_Parameter)
	{
	    case BLE_PARAM_CONNECT_STATE:
		if(m_u16_ConnectHandle == INVALID_HANDLE)
			*u8p_Value = 0;
		else
			*u8p_Value = 1;
		break;      
	    case BLE_PARAM_CONNECT_INTERVAL:
		*(uint16 *)u8p_Value =  m_u16_ConnectInterval;
		break;
		
	    default:
		break;
	}
	return FUNCTION_OK;
}

///////////////////////////////////////////////
void hci_le_connection_complete_event(uint8_t Status,
				      uint16_t Connection_Handle,
				      uint8_t Role,
				      uint8_t Peer_Address_Type,
				      uint8_t Peer_Address[6],
				      uint16_t Conn_Interval,
				      uint16_t Conn_Latency,
				      uint16_t Supervision_Timeout,
				      uint8_t Master_Clock_Accuracy)
{
	LOG_INFO("hci_le_connection_complete_event\n");
	Ble_OnEvent(sl_bt_evt_connection_opened_id ,Connection_Handle,0,0) ;
}
void hci_disconnection_complete_event(uint8_t Status,
				      uint16_t Connection_Handle,
				      uint8_t Reason)
{
	LOG_INFO("hci_disconnection_complete_event\n");
	Ble_OnEvent(sl_bt_evt_connection_closed_id ,0,0,0) ;
}
void aci_gatt_srv_attribute_modified_event(uint16_t Connection_Handle,
					   uint16_t Attr_Handle,
					   uint16_t Attr_Data_Length,
					   uint8_t Attr_Data[])
{
	LOG_INFO("aci_gatt_srv_attribute_modified_event\n");
	Ble_OnEvent(sl_bt_evt_gatt_server_attribute_value_id ,0,0,0) ;
	OTA_Write_Request_CB(Connection_Handle, Attr_Handle, Attr_Data_Length, Attr_Data); 
}
void aci_hal_end_of_radio_activity_event(uint8_t Last_State,
					 uint8_t Next_State,
					 uint32_t Next_State_SysTime)
{
	LOG_INFO("aci_hal_end_of_radio_activity_event\n");
	if (Next_State == 0x02) /* 0x02: Connection event slave */
	{
		OTA_Radio_Activity(Next_State_SysTime);  
	}
	
}
void aci_l2cap_connection_update_resp_event(uint16_t Connection_Handle,
					    uint16_t Result)
{
	LOG_INFO("aci_l2cap_connection_update_resp_event; 0x%02x\r\n", Result);
}

void aci_l2cap_command_reject_event(uint16_t Connection_Handle,
				    uint8_t Identifier,
				    uint16_t Reason,
				    uint8_t Data_Length,
				    uint8_t Data[])
{
	LOG_INFO("aci_l2cap_command_reject_event; 0x%02x\r\n", Reason);
}

void hci_le_connection_update_complete_event(uint8_t Status,
					     uint16_t Connection_Handle,
					     uint16_t Conn_Interval,
					     uint16_t Conn_Latency,
					     uint16_t Supervision_Timeout)
{
	LOG_INFO("hci_le_connection_update_complete_event; %d\r\n", Conn_Interval);
	Conn_Interval = CONNECT_MS_TO_INTERVAL(Conn_Interval) ;
	Supervision_Timeout = CONNECT_MS_TO_INTERVAL(Supervision_Timeout) ;
	LOG_INFO("Conn_Interval:%d ,Conn_Latency:%d ,Supervision_Timeout:%d\r\n", Conn_Interval,Conn_Latency,Supervision_Timeout);
	Ble_OnEvent(sl_bt_evt_connection_parameters_id ,Conn_Interval,Conn_Latency,Supervision_Timeout) ;
}


void aci_att_exchange_mtu_resp_event(uint16_t Connection_Handle,
				     uint16_t Server_RX_MTU)
{
	LOG_INFO("aci_att_exchange_mtu_resp_event\n");
	Ble_OnEvent(sl_bt_evt_gatt_mtu_exchanged_id ,Server_RX_MTU,0,0) ;
	OTA_att_exchange_mtu_resp_CB(Connection_Handle, Server_RX_MTU);
}

void hci_le_data_length_change_event(uint16_t Connection_Handle,
				     uint16_t MaxTxOctets,
				     uint16_t MaxTxTime,
				     uint16_t MaxRxOctets,
				     uint16_t MaxRxTime)
{
	LOG_INFO("hci_le_data_length_change_event\n");
	OTA_data_length_change_CB(Connection_Handle);  
}

void aci_gatt_srv_write_event(uint16_t Connection_Handle, uint8_t Resp_Needed, uint16_t Attribute_Handle, uint16_t Data_Length, uint8_t Data[])
{
	static uint8_t u8_count = 0 ;
	uint8_t att_error = BLE_ATT_ERR_NONE;
	
	OTA_Write_Request_CB(Connection_Handle, Attribute_Handle, Data_Length, Data); 
	if(Attribute_Handle == cgmcommCharHandle + 1)
	{
		LOG_INFO("ser1\n");
		for(uint i=0;i<Data_Length;i++)
		{
			LOG_INFO("Data[%d] = %d\n" ,i,Data[i]);
		}
	}
	else if(Attribute_Handle == cgmmanageCharHandle + 1)
	{
		LOG_INFO("ser2\n");
		for(uint i=0;i<Data_Length;i++)
		{
			LOG_INFO("Data[%d] = %d\n" ,i,Data[i]);
		}
	}
	
	if (Resp_Needed == 1U)
	{
		aci_gatt_srv_resp(Connection_Handle, 0, att_error, 0, NULL);
	}
}

void aci_gatt_srv_read_event(uint16_t Connection_Handle, uint16_t Attribute_Handle, uint16_t Data_Offset)
{
	uint8_t att_err;
	uint8_t buff[6], *data_p;
	uint16_t data_len;
	
	
	att_err = BLE_ATT_ERR_NONE;
	if(Attribute_Handle == cgmcommCharHandle + 1)
	{
		
	}
	else if(Attribute_Handle == cgmmanageCharHandle + 1)
	{
		
	}
	
	OTA_Read_Char(Connection_Handle, Attribute_Handle,Data_Offset);
	LOG_INFO("data_p: %d\n",*data_p);
	aci_gatt_srv_resp(Connection_Handle, Attribute_Handle, att_err, data_len, data_p);
}


//Private function definition  
static void Ble_OnEvent
(
ble_event event ,uint16 para1,uint16 para2,uint16 para3
)
{
	uint16 u16_Handle ;
	switch (event) 
	{
	    case sl_bt_evt_system_boot_id:
		
		break;
	    case sl_bt_evt_connection_opened_id:
		m_u16_ConnectHandle = para1 ;
		uint ret = aci_l2cap_connection_parameter_update_req(m_u16_ConnectHandle, CONNECT_INTERVAL_TO_MS(CONNECT_INTERVAL_MIX), CONNECT_INTERVAL_TO_MS(CONNECT_INTERVAL_MAX), CONNECT_LATENCY, CONNECT_TIMEOUT_TO_MS(CONNECT_TIMEOUT_MAX)));
	    LOG_INFO("aci_l2cap_connection_parameter_update_req(): 0x%02x\r\n", ret);
	    break;
	    case sl_bt_evt_connection_parameters_id:
		m_u16_ConnectInterval = para1;
		m_u16_ConnectLatency = para2;
		m_u16_ConnectTimeout = para3;
		break;
	    case sl_bt_evt_gatt_mtu_exchanged_id:
		m_u16_Mtu = para1 ;
		break;
		
	    case sl_bt_evt_connection_closed_id:
		m_u16_ConnectHandle = INVALID_HANDLE;
		Ble_StartAdv();
		break;
		
	    case sl_bt_evt_gatt_server_characteristic_status_id:
		break;
	    case sl_bt_evt_gatt_server_attribute_value_id:
		break;
	    case sl_bt_evt_gatt_server_user_write_request_id:
		
	    default:
		break;
	}
}

static void Ble_LoadSerialNumber(void)
{
	//    uint8 u8_Buffer[SERIAL_NAME_SIZE]={0};
	//    if(Record_LoadSerialNumber(u8_Buffer,SERIAL_NAME_SIZE+1))
	//    {
	//        if(Lib_Memcmpv(u8_Buffer,FLASH_ERASE_VALUE,SERIAL_NAME_SIZE) == FUNCTION_FAIL)
	//        {
	//            Lib_Memcpy(m_u8p_SerialName,u8_Buffer,SERIAL_NAME_SIZE);
	//        }
	//    }
}


static void Ble_StartAdv(void)
{
	uint ret ;
	Advertising_Set_Parameters[0].Advertising_Handle = 0;
	Advertising_Set_Parameters[0].Duration = 0;
	Advertising_Set_Parameters[0].Max_Extended_Advertising_Events = 0;
	
	ret = aci_gap_set_advertising_enable(ENABLE, 1, Advertising_Set_Parameters); 
	
	if(ret != BLE_STATUS_SUCCESS)
	{
		PRINTF("aci_gap_set_advertising_enable() failed: 0x%02x\r\n",ret);
		BSP_LED_On(BSP_LED3);  
	}
	else
		PRINTF("aci_gap_set_advertising_enable() --> SUCCESS\r\n");
}
static uint Add_CGM_Sensor_Service(void)
{
	uint ret;
	
	ret = aci_gatt_srv_add_service(&env_service);
	if (ret != BLE_STATUS_SUCCESS)
	{
		goto fail;
	}
	
	cgmSensServHandle = aci_gatt_srv_get_service_handle(&env_service);
	cgmcommCharHandle = aci_gatt_srv_get_char_decl_handle(&env_chars[0]);
	cgmmanageCharHandle = aci_gatt_srv_get_char_decl_handle(&env_chars[1]);
	
	return BLE_STATUS_SUCCESS; 
	
    fail:
	PRINTF("Error while adding ENV_SENS service.\n");
	return BLE_STATUS_ERROR;
}
